1   /*
2    * Copyright (C) 2011 The Guava Authors
3    *
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    * http://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  
17  package com.google.common.collect;
18  
19  import static java.util.concurrent.TimeUnit.HOURS;
20  
21  import com.google.common.annotations.GwtCompatible;
22  import com.google.common.base.Function;
23  
24  import junit.framework.TestCase;
25  
26  import java.util.Map;
27  import java.util.concurrent.ConcurrentHashMap;
28  import java.util.concurrent.ConcurrentMap;
29  
30  /**
31   * @author Charles Fry
32   */
33  @GwtCompatible(emulated = true)
34  public class MapMakerTest extends TestCase {
35  
36    // "Basher tests", where we throw a bunch of stuff at a Cache and check basic invariants.
37  
38    /*
39     * TODO(cpovirk): eliminate duplication between these tests and those in LegacyMapMakerTests and
40     * anywhere else
41     */
42  
43    /** Tests for the builder. */
44    public static class MakerTest extends TestCase {
45      public void testInitialCapacity_negative() {
46        MapMaker maker = new MapMaker();
47        try {
48          maker.initialCapacity(-1);
49          fail();
50        } catch (IllegalArgumentException expected) {
51        }
52      }
53  
54      // TODO(cpovirk): enable when ready
55      public void xtestInitialCapacity_setTwice() {
56        MapMaker maker = new MapMaker().initialCapacity(16);
57        try {
58          // even to the same value is not allowed
59          maker.initialCapacity(16);
60          fail();
61        } catch (IllegalArgumentException expected) {
62        }
63      }
64  
65      @SuppressWarnings("deprecation") // test of deprecated method
66      public void testExpiration_setTwice() {
67        MapMaker maker = new MapMaker().expireAfterWrite(1, HOURS);
68        try {
69          // even to the same value is not allowed
70          maker.expireAfterWrite(1, HOURS);
71          fail();
72        } catch (IllegalStateException expected) {
73        }
74      }
75  
76      public void testMaximumSize_setTwice() {
77        MapMaker maker = new MapMaker().maximumSize(16);
78        try {
79          // even to the same value is not allowed
80          maker.maximumSize(16);
81          fail();
82        } catch (IllegalStateException expected) {
83        }
84      }
85  
86      public void testReturnsPlainConcurrentHashMapWhenPossible() {
87        Map<?, ?> map = new MapMaker()
88            .initialCapacity(5)
89            .makeMap();
90        assertTrue(map instanceof ConcurrentHashMap);
91      }
92    }
93  
94    /** Tests of the built map with maximumSize. */
95    public static class MaximumSizeTest extends TestCase {
96      public void testPut_sizeIsZero() {
97        ConcurrentMap<Object, Object> map =
98            new MapMaker().maximumSize(0).makeMap();
99        assertEquals(0, map.size());
100       map.put(new Object(), new Object());
101       assertEquals(0, map.size());
102     }
103 
104     public void testSizeBasedEviction() {
105       int numKeys = 10;
106       int mapSize = 5;
107       ConcurrentMap<Object, Object> map =
108           new MapMaker().maximumSize(mapSize).makeMap();
109       for (int i = 0; i < numKeys; i++) {
110         map.put(i, i);
111       }
112       assertEquals(mapSize, map.size());
113       for (int i = numKeys - mapSize; i < mapSize; i++) {
114         assertTrue(map.containsKey(i));
115       }
116     }
117   }
118 
119   /** Tests for recursive computation. */
120   public static class RecursiveComputationTest extends TestCase {
121     Function<Integer, String> recursiveComputer
122         = new Function<Integer, String>() {
123       @Override
124       public String apply(Integer key) {
125         if (key > 0) {
126           return key + ", " + recursiveMap.get(key - 1);
127         } else {
128           return "0";
129         }
130       }
131     };
132 
133     ConcurrentMap<Integer, String> recursiveMap = new MapMaker()
134         .makeComputingMap(recursiveComputer);
135 
136     public void testRecursiveComputation() {
137       assertEquals("3, 2, 1, 0", recursiveMap.get(3));
138     }
139   }
140 
141   /**
142    * Tests for computing functionality.
143    */
144   public static class ComputingTest extends TestCase {
145     public void testComputerThatReturnsNull() {
146       ConcurrentMap<Integer, String> map = new MapMaker()
147           .makeComputingMap(new Function<Integer, String>() {
148             @Override
149             public String apply(Integer key) {
150               return null;
151             }
152           });
153       try {
154         map.get(1);
155         fail();
156       } catch (NullPointerException e) { /* expected */ }
157     }
158 
159     public void testRuntimeException() {
160       final RuntimeException e = new RuntimeException();
161 
162       ConcurrentMap<Object, Object> map = new MapMaker().makeComputingMap(
163           new Function<Object, Object>() {
164         @Override
165         public Object apply(Object from) {
166           throw e;
167         }
168       });
169 
170       try {
171         map.get(new Object());
172         fail();
173       } catch (ComputationException ce) {
174         assertSame(e, ce.getCause());
175       }
176     }
177   }
178 }
179